﻿Imports System.Xml
Imports pli2cob.clsJustifyStatement
''' <summary>
''' DO...END代码段
''' </summary>
''' <remarks></remarks>
Public Class clsStatementBlock
    Inherits clsSyntaxNode
    ''' <summary>
    ''' 单步列表
    ''' </summary>
    ''' <remarks></remarks>
    Public SingleStatementList As New List(Of XmlElement)
    ''' <summary>
    ''' 块列表
    ''' </summary>
    ''' <remarks></remarks>
    Public BlockOprList As New List(Of clsSyntaxNode)
    ''' <summary>
    ''' 是否为顶层的语句块
    ''' </summary>
    ''' <remarks></remarks>
    Public IsTopStatementBlock As Boolean = False
    ''' <summary>
    ''' 增加一个单步操作
    ''' </summary>
    ''' <param name="xmlOpr"></param>
    ''' <remarks></remarks>
    Public Sub AddOperation(ByVal xmlOpr As XmlElement)
        SingleStatementList.Add(xmlOpr)
    End Sub
    ''' <summary>
    ''' 增加一个IF块
    ''' </summary>
    ''' <param name="IFBlock"></param>
    ''' <remarks></remarks>
    Public Sub AddIF(ByVal IFBlock As IFNode)
        Dim xmlIF As XmlElement = mXmlDocument.CreateElement("IF")
        xmlIF.SetAttribute("BLOCKINDEX", BlockOprList.Count)
        SingleStatementList.Add(xmlIF)
        BlockOprList.Add(IFBlock)
    End Sub
    ''' <summary>
    ''' 增加一个SELECT块
    ''' </summary>
    ''' <param name="SelectBlock"></param>
    ''' <remarks></remarks>
    Public Sub AddSelect(ByVal SelectBlock As SelectNode)
        Dim xmlSelect As XmlElement = mXmlDocument.CreateElement("SELECT")
        xmlSelect.SetAttribute("BLOCKINDEX", BlockOprList.Count)
        SingleStatementList.Add(xmlSelect)
        BlockOprList.Add(SelectBlock)
    End Sub
    ''' <summary>
    ''' 增加一个循环块
    ''' </summary>
    ''' <param name="LoopBlock"></param>
    ''' <remarks></remarks>
    Public Sub AddLoop(ByVal LoopBlock As LoopNode)
        Dim xmlLoop As XmlElement = mXmlDocument.CreateElement("LOOP")
        xmlLoop.SetAttribute("BLOCKINDEX", BlockOprList.Count)
        SingleStatementList.Add(xmlLoop)
        BlockOprList.Add(LoopBlock)
    End Sub
    ''' <summary>
    ''' 调整Section
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub JustifySection()
        Dim NewSection As New clsStatementBlock
        Dim Preprocess As New clsStatementBlock
        Dim Afterprocess As New clsStatementBlock
        Dim HasLabel As Boolean = False
        Dim LabelName As String = String.Empty
        Dim IsNeedNewSection As Boolean = False
        For Each SingleStatementXml As XmlElement In SingleStatementList
            Select Case SingleStatementXml.Name
                Case "IF"
                    Dim mIFNode As IFNode
                    mIFNode = BlockOprList(CInt(SingleStatementXml.GetAttribute("BLOCKINDEX")))
                    '检查所有IF条件,是否有VERIFY
                    mIFNode.IFCondition.ConditionProcess(mIFNode.IFCondition.CondXml, mIFNode.PreProcessList, mIFNode.AfterProcessList)
                    mIFNode.TrueOperationList.JustifySection()
                    mIFNode.FalseOperationList.JustifySection()
                    NewSection.AddIF(mIFNode)
                Case "LOOP"
                    Dim mLoopNode As LoopNode
                    mLoopNode = BlockOprList(CInt(SingleStatementXml.GetAttribute("BLOCKINDEX")))
                    If Not mLoopNode.WhileCondition Is Nothing Then
                        mLoopNode.WhileCondition.ConditionProcess(mLoopNode.WhileCondition.CondXml, mLoopNode.PreProcessList, mLoopNode.AfterProcessList)
                    End If
                    mLoopNode.LoopList.JustifySection()
                    NewSection.AddLoop(mLoopNode)
                Case "SELECT"
                    Dim mSelectNode As SelectNode
                    mSelectNode = BlockOprList(CInt(SingleStatementXml.GetAttribute("BLOCKINDEX")))
                    '增加对SWITCH CONDITION的调整
                    mSelectNode.SwitchCondition = clsJustifyStatement.ModifySubExpress(mSelectNode.SwitchCondition, Preprocess, Afterprocess)
                    For Each strSwitch As SelectNode.StruCase In mSelectNode.SwitchCaseList
                        strSwitch.Condition.ConditionProcess(strSwitch.Condition.CondXml, mSelectNode.PreProcessList, mSelectNode.AfterProcessList)
                        strSwitch.CaseList.JustifySection()
                    Next
                    NewSection.AddSelect(mSelectNode)
                Case "ACCEPT"
                    Dim rtnAccept As XmlElement = clsStatementAccept.JustifyAccept(SingleStatementXml, Preprocess, Afterprocess)
                    MergeStatementBlock(Preprocess, NewSection)
                    MergeStatementBlock(NewSection, Afterprocess)
                Case "CALL"
                    Dim rtnCall As XmlElement = clsStatementCall.JustifyCall(SingleStatementXml, Preprocess, Afterprocess)
                    MergeStatementBlock(Preprocess, NewSection)
                    NewSection.AddOperation(rtnCall)
                Case "COMPUTE"
                    Dim rtnCompute As XmlElement = clsStatementCompute.JustifyCompute(SingleStatementXml, Preprocess, Afterprocess)
                    If Preprocess.Count > 0 Then
                        Dim DummyNode As XmlElement = rtnCompute.CloneNode(False)
                        For Each SubXml As XmlNode In rtnCompute.ChildNodes
                            If SubXml.Name = "COMMENTLIST" Then
                                Preprocess.SingleStatementList(0).AppendChild(SubXml.Clone)
                            Else
                                DummyNode.AppendChild(SubXml.Clone)
                            End If
                        Next
                        rtnCompute = DummyNode
                    End If
                    MergeStatementBlock(Preprocess, NewSection)
                    MergeStatementBlock(NewSection, Afterprocess)
                Case "INIT"
                    Dim rtnInti As Object = clsStatementInit.JustifyInit(SingleStatementXml, Preprocess, Afterprocess)
                    If rtnInti.GetType Is GetType(LoopNode) Then
                        '如果返回Loop节的情况
                        MergeStatementBlock(Preprocess, NewSection)
                        NewSection.AddLoop(rtnInti)
                        MergeStatementBlock(NewSection, Afterprocess)
                    Else
                        MergeStatementBlock(Preprocess, NewSection)
                        NewSection.AddOperation(rtnInti)
                        MergeStatementBlock(NewSection, Afterprocess)
                    End If
                Case "LABEL"
                    '具有LABEL
                    HasLabel = True
                    LabelName = SingleStatementXml.GetAttribute("LABEL")
                    NewSection.AddOperation(SingleStatementXml)
                Case "MOVE"
                    Dim rtnResult As Object = clsStatementMove.JustifyMove(SingleStatementXml, Preprocess, Afterprocess)
                    If rtnResult.GetType Is GetType(LoopNode) Then
                        '如果返回Loop节的情况
                        MergeStatementBlock(Preprocess, NewSection)
                        NewSection.AddLoop(rtnResult)
                        MergeStatementBlock(NewSection, Afterprocess)
                    Else
                        Dim rtnMoveXml As XmlElement = rtnResult
                        If Preprocess.Count > 0 Then
                            Dim DummyNode As XmlElement = rtnMoveXml.CloneNode(False)
                            For Each SubXml As XmlNode In rtnMoveXml.ChildNodes
                                If SubXml.Name = "COMMENTLIST" Then
                                    Preprocess.SingleStatementList(0).AppendChild(SubXml.Clone)
                                Else
                                    DummyNode.AppendChild(SubXml.Clone)
                                End If
                            Next
                            rtnMoveXml = DummyNode
                        End If
                        MergeStatementBlock(Preprocess, NewSection)
                        NewSection.AddOperation(rtnMoveXml)
                        MergeStatementBlock(NewSection, Afterprocess)
                    End If
                Case "MACRO"
                    Dim rtnMacro As XmlElement = clsStatementMacro.JustifyMacro(SingleStatementXml, Preprocess, Afterprocess)
                    MergeStatementBlock(Preprocess, NewSection)
                    NewSection.AddOperation(rtnMacro)
                Case "PUT", "GET"
                    'PUT/GET将不复存在,返回的是一个非常复杂的过程
                    Dim rtnStatement As clsStatementBlock
                    If SingleStatementXml.Name = "PUT" Then
                        rtnStatement = clsStatementPut.JustifyPut(SingleStatementXml)
                    Else
                        rtnStatement = clsStatementGet.JustifyGet(SingleStatementXml)
                    End If
                    MergeStatementBlock(NewSection, rtnStatement)
                Case "SET"
                    Dim rtnSet As XmlElement = clsStatementSet.JustifySet(SingleStatementXml, Preprocess, Afterprocess)
                    NewSection.AddOperation(rtnSet)
                        MergeStatementBlock(NewSection, Afterprocess)
                Case Else
                    NewSection.AddOperation(SingleStatementXml)
            End Select
            Preprocess.Clear()
            Afterprocess.Clear()
        Next
        If HasLabel Then
            '如果具有标签，但是这个语句块不是顶层的情况下，需要将所有的LABEL后面的语句放入新的SECTION
            '需要注意LABEL和GOTO的位置关系
            Dim NewLabelSection As New SectionNode With {.SectionName = LabelName}
            Dim ProcessInLabel As Boolean = False
            Dim IsLabelEnd As Boolean = False
            BlockOprList.Clear()
            SingleStatementList.Clear()
            For Each SingleStatement In NewSection.SingleStatementList
                Select Case SingleStatement.Name
                    Case "IF"
                        Dim mIFNode As IFNode
                        mIFNode = NewSection.BlockOprList(CInt(SingleStatement.GetAttribute("BLOCKINDEX")))
                        If ProcessInLabel And Not IsTopStatementBlock Then
                            NewLabelSection.AddIF(mIFNode)
                        Else
                            Me.AddIF(mIFNode)
                        End If
                    Case "LOOP"
                        Dim mLoopNode As LoopNode
                        mLoopNode = NewSection.BlockOprList(CInt(SingleStatement.GetAttribute("BLOCKINDEX")))
                        If ProcessInLabel And Not IsTopStatementBlock Then
                            NewLabelSection.AddLoop(mLoopNode)
                        Else
                            Me.AddLoop(mLoopNode)
                        End If
                    Case "SELECT"
                        Dim mSELECTNode As SelectNode
                        mSELECTNode = NewSection.BlockOprList(CInt(SingleStatement.GetAttribute("BLOCKINDEX")))
                        If ProcessInLabel And Not IsTopStatementBlock Then
                            NewLabelSection.AddSelect(mSELECTNode)
                        Else
                            Me.AddSelect(mSELECTNode)
                        End If
                    Case "GOTO"
                        '改GOTO为CALL
                        Me.AddOperation(SingleStatement)
                        ProcessInLabel = False
                        If NewLabelSection.Count <> 0 Then
                            'GOTO之前有LABEL的情况,遇上GOTO的话，LABEL就结束了
                            IsLabelEnd = True
                        End If
                        Dim LabelXml As XmlElement = mXmlDocument.CreateElement("LABEL")
                        LabelXml.SetAttribute("LABEL", LabelName)
                        LabelXml.SetAttribute("END", True)
                        If IsTopStatementBlock Then
                            Me.AddOperation(LabelXml)
                        End If
                    Case "LABEL"
                        ProcessInLabel = True
                        If IsTopStatementBlock Then
                            Me.AddOperation(SingleStatement)
                        End If
                    Case Else
                        If ProcessInLabel And Not IsTopStatementBlock Then
                            NewLabelSection.AddOperation(SingleStatement)
                        Else
                            Me.AddOperation(SingleStatement)
                        End If
                End Select
            Next
            '如果是非顶层语句块，则添加一个Section
            If IsTopStatementBlock = False Then
                mProcedureNode.AddSection(NewLabelSection)
            Else
                If ProcessInLabel Then
                    Dim LabelXml As XmlElement = mXmlDocument.CreateElement("LABEL")
                    LabelXml.SetAttribute("LABEL", LabelName)
                    LabelXml.SetAttribute("END", True)
                    Me.AddOperation(LabelXml)
                End If
            End If
            Exit Sub
        End If
        SingleStatementList.Clear()
        BlockOprList.Clear()
        SingleStatementList = NewSection.SingleStatementList
        BlockOprList = NewSection.BlockOprList
    End Sub
    ''' <summary>
    ''' 获得COBOL的代码
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function Convert2Cobol() As System.Collections.Generic.List(Of String)
        Dim strCobol As New List(Of String)
        For Each oprXml As XmlElement In SingleStatementList
            Select Case oprXml.Name
                Case "IF", "SELECT", "LOOP"
                    For Each str As String In BlockOprList(CInt(oprXml.GetAttribute("BLOCKINDEX"))).Convert2Cobol
                        strCobol.Add(str)
                    Next
                Case Else
                    For Each str As String In GetCobolByTag(oprXml)
                        strCobol.Add(str)
                    Next
            End Select
        Next
        Return strCobol
    End Function
    ''' <summary>
    ''' 根据命令种类生成COBOL语句
    ''' </summary>
    ''' <param name="StatemenetXml"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetCobolByTag(ByVal StatemenetXml As XmlElement) As List(Of String)
        Dim strCobol As New List(Of String)
        '整行注释或者预处理动作的追加
        For Each SubStatementXML As XmlElement In StatemenetXml.ChildNodes
            If SubStatementXML.Name = "COMMENTLIST" Then
                '整行注释
                strCobol.Add(FormatCOBOLComment(SubStatementXML.GetAttribute("TEXT")))
            End If
        Next
        If StatemenetXml.GetAttribute("COMMENT") <> String.Empty Then
            strCobol.Add(GetSpace() & StatemenetXml.GetAttribute("COMMENT"))
        End If
        Dim strStatement As New List(Of String)
        Select Case StatemenetXml.Name
            Case "ACCEPT"
                strStatement = clsStatementAccept.GenerateACCEPT(StatemenetXml)
            Case "CALL"
                strStatement = clsStatementCall.GenerateCALL(StatemenetXml)
            Case "CLOSE"
                strStatement = clsStatementClose.GenerateCLOSE(StatemenetXml)
            Case "COMPUTE"
                strStatement = clsStatementCompute.GenerateCOMPUTE(StatemenetXml)
            Case "DISPLAY"
                strStatement = clsStatementDisplay.GenerateDISPLAY(StatemenetXml)
            Case "ADD", "SUBTRACT", "DIVIDE", "MULTIPLY"
                strStatement = clsStatementCompute.GenerateFUNC(StatemenetXml)
            Case "EXEC"
                strStatement = clsStatementEXEC.GenerateEXEC(StatemenetXml)
            Case "FUNCTION"
                strStatement = clsStatementFunction.GenerateFunction(StatemenetXml)
            Case "GOTO"
                strStatement = clsStatementGoto.GenerateGOTO(StatemenetXml)
            Case "INIT"
                strStatement = clsStatementInit.GenerateINIT(StatemenetXml)
            Case "INCLUDE"
                strStatement = clsStatementInclude.GenerateINCLUDE(StatemenetXml)
            Case "LABEL"
                strStatement = clsStatementLabel.GenerateLABEL(StatemenetXml)
            Case "LEAVE"
                strStatement = clsStatementLeave.GenerateLeave(StatemenetXml)
            Case "MOVE"
                strStatement = clsStatementMove.GenerateMOVE(StatemenetXml)
            Case "MACRO"
                strStatement = clsJRIProject.Convert2Cobol(StatemenetXml)
            Case "OPEN"
                strStatement = clsStatementOpen.GenerateOPEN(StatemenetXml)
            Case "READ"
                strStatement = clsStatementRead.GenerateREAD(StatemenetXml)
            Case "SET"
                strStatement = clsStatementSet.GenerateSET(StatemenetXml)
            Case "STRING"
                strStatement = clsStatementMove.GenerateSTRING(StatemenetXml)
            Case "WRITE"
                strStatement = clsStatementWrite.GenerateWRITE(StatemenetXml)
            Case "ENDFILE", "FETCH"
                'ON ENDFILE 条件语句
                'FETCH      动态调用
                'PUT/GET    转换为其他COBOL语句
                'ROUND      改为COMPUTE ROUNDED
            Case Else
                strStatement.Add((GetSpace() & StatemenetXml.GetAttribute("Statement").Replace(";", ".")))
        End Select
        For Each strLine As String In strStatement
            strCobol.Add(strLine)
        Next
        Return strCobol
    End Function
    ''' <summary>
    ''' 获得语法树的XML节点
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function GetXMLElement() As System.Xml.XmlElement
        Dim RootXml As XmlElement = mXmlDocument.CreateElement("DO")
        For Each oprXml As XmlElement In SingleStatementList
            Select Case oprXml.Name
                Case "IF", "SELECT", "LOOP"
                    RootXml.AppendChild(BlockOprList(CInt(oprXml.GetAttribute("BLOCKINDEX"))).GetXMLElement)
                Case Else
                    RootXml.AppendChild(oprXml)
            End Select
        Next
        Return RootXml
    End Function
    ''' <summary>
    ''' 单行语句列表长度
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    ReadOnly Property Count() As Integer
        Get
            Return SingleStatementList.Count
        End Get
    End Property
    ''' <summary>
    ''' 清空语句列表
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Clear()
        SingleStatementList.Clear()
        BlockOprList.Clear()
    End Sub
End Class
''' <summary>
''' IF节点类
''' </summary>
''' <remarks></remarks>
Public Class IFNode
    Inherits clsSyntaxNode
    ''' <summary>
    ''' 条件式预处理
    ''' </summary>
    ''' <remarks></remarks>
    Public PreProcessList As New clsStatementBlock
    ''' <summary>
    ''' 条件式后处理
    ''' </summary>
    ''' <remarks></remarks>
    Public AfterProcessList As New clsStatementBlock
    ''' <summary>
    ''' True的动作列表
    ''' </summary>
    ''' <remarks></remarks>
    Public TrueOperationList As New clsStatementBlock
    ''' <summary>
    ''' False的动作列表
    ''' </summary>
    ''' <remarks></remarks>
    Public FalseOperationList As New clsStatementBlock
    ''' <summary>
    ''' IF条件
    ''' </summary>
    ''' <remarks></remarks>
    Public IFCondition As ConditionNode
    ''' <summary>
    ''' 获得COBOL的代码
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function Convert2Cobol() As List(Of String)
        Dim strCobol As New List(Of String)
        For Each CommentXML As XmlElement In CommentList
            strCobol.Add(FormatCOBOLComment(CommentXML.GetAttribute("TEXT")))
        Next
        '预处理
        For Each Str As String In PreProcessList.Convert2Cobol
            strCobol.Add(Str)
        Next
        Dim ConditionArray As List(Of String) = IFCondition.Convert2Cobol
        If ConditionArray.Count = 1 Then
            strCobol.Add(GetSpace() & "IF" & Space(Indent) & ConditionArray(0) & Space(Indent) & "THEN")
        Else
            strCobol.Add(GetSpace() & "IF" & Space(Indent) & ConditionArray(0))
            For ConditionCount As Byte = 1 To ConditionArray.Count - 2
                strCobol.Add(GetSpace() & Space(Indent + 2) & ConditionArray(ConditionCount) & Space(Indent))
            Next
            strCobol.Add(GetSpace() & Space(Indent + 2) & ConditionArray(ConditionArray.Count - 1) & Space(Indent) & "THEN")
        End If
        Deepth += 1
        If TrueOperationList.Count > 0 Then
            For Each Str As String In TrueOperationList.Convert2Cobol
                strCobol.Add(Str)
            Next
        Else
            strCobol.Add(GetSpace() & "CONTINUE")
        End If
        Deepth -= 1
        If FalseOperationList.Count > 0 Then
            strCobol.Add(GetSpace() & "ELSE")
            Deepth += 1
            For Each Str As String In FalseOperationList.Convert2Cobol
                strCobol.Add(Str)
            Next
            Deepth -= 1
        Else
            If AddContinueForEmptyElse Then
                strCobol.Add(GetSpace() & "ELSE")
                Deepth += 1
                strCobol.Add(GetSpace() & "CONTINUE")
                Deepth -= 1
            End If
        End If
        strCobol.Add(GetSpace() & "END-IF" & IIf(Deepth = 1, ".", String.Empty))
        '后处理
        For Each Str As String In AfterProcessList.Convert2Cobol
            strCobol.Add(Str)
        Next
        Return strCobol
    End Function
    ''' <summary>
    ''' 获得语法树的XML节点
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function GetXMLElement() As System.Xml.XmlElement
        Dim mRootElement As XmlElement
        mRootElement = mXmlDocument.CreateElement("IF")
        mRootElement.AppendChild(IFCondition.GetXMLElement)
        'CommentList
        Dim mCommentElement As XmlElement
        mCommentElement = mXmlDocument.CreateElement("COMMENTLIST")
        For Each mComList As XmlElement In CommentList
            mCommentElement.AppendChild(mComList)
        Next
        mRootElement.AppendChild(mCommentElement)
        '条件预处理
        mRootElement.AppendChild(PreProcessList.GetXMLElement)
        '真的处理
        If TrueOperationList.Count > 0 Then
            Dim mTrueElement As XmlElement
            mTrueElement = mXmlDocument.CreateElement("TRUE")
            mTrueElement.AppendChild(TrueOperationList.GetXMLElement)
            mRootElement.AppendChild(mTrueElement)
        End If
        '伪的处理
        If FalseOperationList.Count > 0 Then
            Dim mFalseElement As XmlElement
            mFalseElement = mXmlDocument.CreateElement("FALSE")
            mFalseElement.AppendChild(FalseOperationList.GetXMLElement)
            mRootElement.AppendChild(mFalseElement)
        End If
        '条件后处理
        mRootElement.AppendChild(AfterProcessList.GetXMLElement)
        Return mRootElement
    End Function
End Class
''' <summary>
''' SELECT节点类
''' </summary>
''' <remarks></remarks>
Public Class SelectNode
    Inherits clsSyntaxNode
    ''' <summary>
    ''' 条件式预处理
    ''' </summary>
    ''' <remarks></remarks>
    Public PreProcessList As New clsStatementBlock
    ''' <summary>
    ''' 条件式后处理
    ''' </summary>
    ''' <remarks></remarks>
    Public AfterProcessList As New clsStatementBlock
    ''' <summary>
    ''' SELECT列表
    ''' </summary>
    ''' <remarks></remarks>
    Public SwitchCaseList As New List(Of StruCase)
    ''' <summary>
    ''' 每个分支
    ''' </summary>
    ''' <remarks></remarks>
    Structure StruCase
        Dim Condition As ConditionNode
        Dim CaseList As clsStatementBlock
    End Structure
    ''' <summary>
    ''' Switch变量
    ''' </summary>
    ''' <remarks></remarks>
    Public SwitchCondition As String
    ''' <summary>
    ''' 获得COBOL的代码
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function Convert2Cobol() As List(Of String)
        Dim strCobol As New List(Of String)
        Dim HasOther As Boolean = False
        For Each CommentXML As XmlElement In CommentList
            strCobol.Add(FormatCOBOLComment(CommentXML.GetAttribute("TEXT")))
        Next
        '预处理
        For Each Str As String In PreProcessList.Convert2Cobol
            strCobol.Add(Str)
        Next
        If SwitchCondition = String.Empty Then
            strCobol.Add(GetSpace() & "EVALUATE  TRUE")
        Else
            strCobol.Add(GetSpace() & "EVALUATE  " & clsJustifyStatement.ModifyVarName(SwitchCondition))
        End If
        For Each CaseElement As StruCase In SwitchCaseList
            If CaseElement.Condition.Convert2Cobol.Item(0) = "OTHERWISE" Then
                strCobol.Add(GetSpace() & "WHEN  OTHER")
                HasOther = True
            Else
                If SwitchCondition = String.Empty Then
                    Dim ConditionArray As List(Of String) = CaseElement.Condition.Convert2Cobol
                    If ConditionArray.Count = 1 Then
                        strCobol.Add(GetSpace() & "WHEN" & Space(Indent) & ConditionArray(0).Trim & Space(Indent))
                    Else
                        strCobol.Add(GetSpace() & "WHEN" & Space(Indent) & ConditionArray(0).Trim)
                        For ConditionCount As Byte = 1 To ConditionArray.Count - 1
                            strCobol.Add(GetSpace() & Space(Indent + 4) & ConditionArray(ConditionCount) & Space(Indent))
                        Next
                    End If
                Else
                    'SELECT多个值对应相同过程的追加
                    Dim SingleConditon As String = CaseElement.Condition.Convert2Cobol.Item(0)
                    If GetSubLinesBySplitMark(SingleConditon, ",", SplitStyle.NoSplitMark).Count = 1 Then
                        strCobol.Add(GetSpace() & "WHEN  " & SingleConditon.Trim)
                    Else
                        For Each strCondition As String In GetSubLinesBySplitMark(SingleConditon, ",", SplitStyle.NoSplitMark)
                            strCobol.Add(GetSpace() & "WHEN  " & strCondition.Trim)
                        Next
                    End If
                End If
            End If
            Deepth += 1
            If CaseElement.CaseList.Count = 0 Then
                strCobol.Add(GetSpace() & "CONTINUE")
            Else
                For Each Str As String In CaseElement.CaseList.Convert2Cobol
                    strCobol.Add(Str)
                Next
            End If
            Deepth -= 1
        Next
        '如果没有OTHERWISE,添加一个OTHERWISE
        If HasOther = False Then
            strCobol.Add(GetSpace() & "WHEN  OTHER")
            Deepth += 1
            strCobol.Add(GetSpace() & "CONTINUE")
            Deepth -= 1
        End If
        strCobol.Add(GetSpace() & "END-EVALUATE" & IIf(Deepth = 1, ".", String.Empty))
        '后处理
        For Each Str As String In AfterProcessList.Convert2Cobol
            strCobol.Add(Str)
        Next
        Return strCobol
    End Function
    ''' <summary>
    ''' 获得语法树的XML节点
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function GetXMLElement() As System.Xml.XmlElement
        Dim mRootElement As XmlElement

        mRootElement = mXmlDocument.CreateElement("SELECT")
        '条件预处理
        mRootElement.AppendChild(PreProcessList.GetXMLElement)

        mRootElement.SetAttribute("SwitchCondition", SwitchCondition)

        'CommentList
        Dim mCommentElement As XmlElement
        mCommentElement = mXmlDocument.CreateElement("COMMENTLIST")
        For Each mComList As XmlElement In CommentList
            mCommentElement.AppendChild(mComList)
        Next
        mRootElement.AppendChild(mCommentElement)
        For Each caseNode As StruCase In SwitchCaseList
            Dim CaseXml As XmlElement = mXmlDocument.CreateElement("WHEN")
            CaseXml.AppendChild(caseNode.Condition.GetXMLElement)
            CaseXml.AppendChild(caseNode.CaseList.GetXMLElement)
            mRootElement.AppendChild(CaseXml)
        Next
        '条件后处理
        mRootElement.AppendChild(AfterProcessList.GetXMLElement)
        Return mRootElement
    End Function
    ''' <summary>
    ''' 增加一个WHEN节点
    ''' </summary>
    ''' <param name="SyntaxNode"></param>
    ''' <remarks></remarks>
    Public Sub AddSwitchItem(ByVal SyntaxNode As StruCase)
        SwitchCaseList.Add(SyntaxNode)
    End Sub
End Class
''' <summary>
''' Loop节点类
''' </summary>
''' <remarks></remarks>
Public Class LoopNode
    Inherits clsSyntaxNode
    ''' <summary>
    ''' 条件式预处理
    ''' </summary>
    ''' <remarks></remarks>
    Public PreProcessList As New clsStatementBlock
    ''' <summary>
    ''' 条件式后处理
    ''' </summary>
    ''' <remarks></remarks>
    Public AfterProcessList As New clsStatementBlock
    ''' <summary>
    ''' While条件
    ''' </summary>
    ''' <remarks></remarks>
    Public WhileCondition As ConditionNode
    ''' <summary>
    ''' Until条件
    ''' </summary>
    ''' <remarks></remarks>
    Public UntilCondition As ConditionNode
    ''' <summary>
    ''' Loop变量名称
    ''' </summary>
    ''' <remarks></remarks>
    Public LoopVarName As String
    ''' <summary>
    ''' Loop的开始值
    ''' </summary>
    ''' <remarks></remarks>
    Public LoopFrom As String = 1
    ''' <summary>
    ''' Loop的结束值
    ''' </summary>
    ''' <remarks></remarks>
    Public LoopTo As String = 1
    ''' <summary>
    ''' Loop的By值
    ''' </summary>
    ''' <remarks></remarks>
    Public LoopBy As String = 1
    ''' <summary>
    ''' 标签名称
    ''' </summary>
    ''' <remarks></remarks>
    Public LabelName As String
    ''' <summary>
    ''' 循环体
    ''' </summary>
    ''' <remarks></remarks>
    Public LoopList As New clsStatementBlock
    ''' <summary>
    ''' 获得COBOL的代码
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function Convert2Cobol() As List(Of String)
        Dim strCobol As New List(Of String)
        '注释 
        For Each CommentXML As XmlElement In CommentList
            strCobol.Add(FormatCOBOLComment(CommentXML.GetAttribute("TEXT")))
        Next
        '后处理
        For Each Str As String In PreProcessList.Convert2Cobol
            strCobol.Add(Str)
        Next
        '前置标签
        If LabelName <> String.Empty Then
            strCobol.Add(Space(LeftStart) & ModifyLabelName(LabelName, False) & ".")
        End If
        '循环条件
        'TODO:WHILE,UNTIL,TO 复杂条件的整理
        '0.UNTIL,WHILE条件不能同时存在    
        '1.如果有UNTIL条件，则需要使用TEST AFTER
        '2.如果BY是负数,注意UNTIL条件需要取反
        Dim IsTestAfter As Boolean = False
        If Not UntilCondition Is Nothing Then
            IsTestAfter = True
        End If
        Dim strPerformCondition As String = String.Empty
        Dim strUntilCondition As String = String.Empty
        Dim UntilConditionList As New List(Of String)

        '循环变量处理
        If LoopFrom <> String.Empty AndAlso LoopTo <> String.Empty AndAlso LoopVarName <> String.Empty Then
            'PERFORM
            strPerformCondition = GetSpace() & "VARYING  %Varname  FROM  %LoopFrom  BY  %LoopBy"
            strPerformCondition = strPerformCondition.Replace("%Varname", clsJustifyStatement.ModifyVarName(LoopVarName))
            strPerformCondition = strPerformCondition.Replace("%LoopFrom", clsJustifyStatement.ModifyVarName(LoopFrom))
            strPerformCondition = strPerformCondition.Replace("%LoopBy", clsJustifyStatement.ModifyVarName(LoopBy))
            'UNTIL
            strUntilCondition = GetSpace() & IIf(IsTestAfter, "WITH  TEST  AFTER  ", String.Empty)
            '如果BY是负数则用NOT
            strUntilCondition &= "UNTIL" & Space(Indent) & IIf(Mid(LoopBy, 1, 1) = "-", "NOT(", String.Empty)
            '根据TestAfter来确定符号
            strUntilCondition &= clsJustifyStatement.ModifyVarName(LoopVarName) & IIf(IsTestAfter, " = ", " > ")
            strUntilCondition &= clsJustifyStatement.ModifyVarName(LoopTo) & IIf(Mid(LoopBy, 1, 1) = "-", ")", String.Empty)
            UntilConditionList.Add(strUntilCondition)
        End If
        'WHILE条件处理
        If Not WhileCondition Is Nothing AndAlso Not (WhileCondition.Convert2Cobol.Count = 0) Then
            Dim ConditionArray As List(Of String) = WhileCondition.Convert2Cobol
            If ConditionArray.Count = 1 Then
                '单条件
                If ConditionArray(0).StartsWith("NOT ") Then
                    '原来条件含有NOT的情况
                    If UntilConditionList.Count = 0 Then
                        If WhileCondition.CondXml.ChildNodes.Count > 0 Then
                            UntilConditionList.Add(GetSpace() & "UNTIL " & Mid(ConditionArray(0), 5))
                        Else
                            UntilConditionList.Add(GetSpace() & "UNTIL (" & Mid(ConditionArray(0), 5) & ")")
                        End If
                    Else
                        UntilConditionList.Add(GetSpace() & "  OR (" & Mid(ConditionArray(0), 5) & ")")
                    End If
                Else
                    '原来条件不含有NOT的情况
                    If UntilConditionList.Count = 0 Then
                        If WhileCondition.CondXml.ChildNodes.Count > 0 Then
                            UntilConditionList.Add("UNTIL  NOT" & ConditionArray(0))
                        Else
                            UntilConditionList.Add("UNTIL  NOT(" & ConditionArray(0) & ")")
                        End If
                    Else
                        UntilConditionList.Add(GetSpace() & "  OR  NOT(" & ConditionArray(0) & ")")
                    End If
                End If
            Else
                '复合条件
                If UntilConditionList.Count = 0 Then
                    If WhileCondition.CondXml.ChildNodes.Count > 0 Then
                        UntilConditionList.Add("UNTIL  NOT" & ConditionArray(0))
                    Else
                        UntilConditionList.Add("UNTIL  NOT(" & ConditionArray(0) & ")")
                    End If
                Else
                    UntilConditionList.Add(GetSpace() & "  OR  NOT(" & Mid(ConditionArray(0), 5))
                End If
                For ConditionCount As Byte = 1 To ConditionArray.Count - 2
                    UntilConditionList.Add(GetSpace() & Space(19) & ConditionArray(ConditionCount) & Space(Indent))
                Next
                If WhileCondition.CondXml.ChildNodes.Count > 0 Then
                    UntilConditionList.Add(GetSpace() & Space(19) & ConditionArray(ConditionArray.Count - 1))
                Else
                    UntilConditionList.Add(GetSpace() & Space(19) & ConditionArray(ConditionArray.Count - 1) & ")")
                End If
            End If
        End If
        'TODO:UNTIL条件处理

        If strPerformCondition = String.Empty Then
            UntilConditionList(0) = GetSpace() & "PERFORM  " & UntilConditionList(0).TrimStart
        Else
            strCobol.Add(GetSpace() & "PERFORM  " & strPerformCondition.TrimStart)
        End If
        For Each strUntil As String In UntilConditionList
            strCobol.Add(strUntil)
        Next
        '循环体
        Deepth += 1
        For Each Str As String In LoopList.Convert2Cobol
            strCobol.Add(Str)
        Next
        Deepth -= 1
        strCobol.Add(GetSpace() & "END-PERFORM" & IIf(Deepth = 1, ".", String.Empty))
        '后置标签
        If LabelName <> String.Empty Then
            strCobol.Add(Space(LeftStart) & ModifyLabelName(LabelName, True) & ".")
        End If
        '后处理
        For Each Str As String In AfterProcessList.Convert2Cobol
            strCobol.Add(Str)
        Next
        Return strCobol
    End Function
    ''' <summary>
    ''' 获得语法树的XML节点
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function GetXMLElement() As System.Xml.XmlElement
        Dim mRootElement As XmlElement
        mRootElement = mXmlDocument.CreateElement("Loop")
        '条件预处理
        mRootElement.AppendChild(PreProcessList.GetXMLElement)

        If Not WhileCondition Is Nothing Then
            mRootElement.AppendChild(WhileCondition.GetXMLElement)
        End If
        If Not UntilCondition Is Nothing Then
            mRootElement.AppendChild(UntilCondition.GetXMLElement)
        End If
        mRootElement.SetAttribute("LoopVarName", LoopVarName)
        mRootElement.SetAttribute("LoopFrom", LoopFrom)
        mRootElement.SetAttribute("LoopTo", LoopTo)
        mRootElement.SetAttribute("LoopBy", LoopBy)
        mRootElement.SetAttribute("LabelName", LabelName)
        'CommentList
        Dim mCommentElement As XmlElement
        mCommentElement = mXmlDocument.CreateElement("COMMENTLIST")
        For Each mComList As XmlElement In CommentList
            mCommentElement.AppendChild(mComList)
        Next
        mRootElement.AppendChild(mCommentElement)
        mRootElement.AppendChild(LoopList.GetXMLElement)
        '条件后处理
        mRootElement.AppendChild(AfterProcessList.GetXMLElement)
        Return mRootElement
    End Function
End Class
''' <summary>
''' 条件表达式节点类
''' </summary>
''' <remarks></remarks>
Public Class ConditionNode
    Inherits clsSyntaxNode
    ''' <summary>
    ''' 条件原文
    ''' </summary>
    ''' <remarks></remarks>
    Public mCondition As String
    ''' <summary>
    ''' 条件XML
    ''' </summary>
    ''' <remarks></remarks>
    Public CondXml As XmlElement
    ''' <summary>
    ''' 实例化新类
    ''' </summary>
    ''' <param name="strCondition"></param>
    ''' <remarks></remarks>
    Sub New(ByVal strCondition As String)
        mCondition = strCondition
        CondXml = GetCondition(mCondition)
    End Sub
    ''' <summary>
    ''' 获得语法树的XML节点
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function GetXMLElement() As System.Xml.XmlElement
        '这里不能使用Return GetCondition(mCondition)
        '不然会造成COBOL的括号丢失和临时变量丢失的可能性
        '原因是第一次生成的CondXml会在ReWriteCondition之前进行一些整理和添加临时变量
        'ReWriteCondition需要使用修改过后的CondXml，如果这里在重新GetCondition的话
        '又变成了没有经过调整的原始的XML结构
        Return CondXml
    End Function
    ''' <summary>
    ''' 格式化条件文字列
    ''' </summary>
    ''' <param name="strCondition"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function GetCondition(ByVal strCondition As String) As XmlElement
        'TODO: BIT转CHAR的影响需要考虑进去
        Dim strConditionList As New List(Of String)
        Dim ConditionArray As New List(Of String)
        Dim OrCount As Byte = 0
        Dim AndCount As Byte = 0
        Dim NotCount As Byte = 0
        Dim EqCount As Byte = 0
        Dim ConNode As XmlElement = mXmlDocument.CreateElement("COND")
        Dim SingleLine As New List(Of String)
        strCondition = strCondition.Replace(NotChar, " NOT ")
        For Each strWord As String In GetSyntaxToken(strCondition)
            Select Case strWord.Trim
                Case "|"
                    ConditionArray.Add("OR")
                    OrCount += 1
                Case "&"
                    ConditionArray.Add("AND")
                    AndCount += 1
                Case "NOT"
                    ConditionArray.Add("NOT")
                    NotCount += 1
                Case "=", "<", ">", "<=", ">="
                    ConditionArray.Add(strWord)
                    EqCount += 1
                Case Else
                    ConditionArray.Add(strWord)
            End Select
        Next
        '1) NOT 
        If NotCount = 1 Then
            Select Case ConditionArray.Count
                Case 2
                    'NOT Var
                    ConNode.SetAttribute("NOT", True)
                    Dim strT As String = ConditionArray(1)
                    '可能是一个括号表达式
                    If strT.StartsWith("(") And strT.EndsWith(")") Then
                        Dim subNode As XmlElement = GetCondition(Mid(strT, 2, strT.Length - 2))
                        Return subNode
                    Else
                        ConNode.SetAttribute("Condition", ConditionArray(1))
                    End If
                    Return ConNode
                Case 4
                    'A NOT opr B
                    If ConditionArray(1).Trim = "NOT" Then
                        ConNode.SetAttribute("NOT", True)
                        ConNode.SetAttribute("Condition", strCondition.Replace(" NOT ", String.Empty))
                        Return ConNode
                    End If
            End Select
        End If
        '2) FLAG
        If ConditionArray.Count = 1 Then
            '可能是一个括号表达式
            Dim strT As String = ConditionArray(0)
            If strT.StartsWith("(") And strT.EndsWith(")") Then
                Dim subNode As XmlElement = GetCondition(Mid(strT, 2, strT.Length - 2))
                Return subNode
            Else
                ConNode.SetAttribute("Condition", strT)
            End If
            Return ConNode
        End If
        '3)不含AND 或者 OR 的代码, A 运算符号 B 的简单模式
        If AndCount + OrCount = 0 Then
            ConNode.SetAttribute("Condition", strCondition)
            Return ConNode
        End If
        '4)由于GetWordList的特性,()做为了个整体 
        '这个版本的转换,只将第一层整理出来
        For Each strWord As String In ConditionArray
            If strWord = "AND" Or strWord = "OR" Then
                Dim SubNode As XmlElement = GetCondition(Join(SingleLine.ToArray))
                SubNode.SetAttribute("LOGIC", strWord)
                ConNode.AppendChild(SubNode)
                SingleLine.Clear()
            Else
                SingleLine.Add(strWord)
            End If
        Next
        Dim LastSubNode As XmlElement = GetCondition(Join(SingleLine.ToArray))
        ConNode.AppendChild(LastSubNode)
        Return ConNode
    End Function
    ''' <summary>
    ''' 获得COBOL的代码
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function Convert2Cobol() As System.Collections.Generic.List(Of String)
        Dim strRtn As List(Of String)
        strRtn = ReWriteCondition(Me.GetXMLElement)
        Return strRtn
    End Function
    ''' <summary>
    ''' 重写条件式
    ''' </summary>
    ''' <param name="CondXml"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ReWriteCondition(ByVal CondXml As XmlElement) As List(Of String)
        Dim rtnCondition As New List(Of String)
        If CondXml.ChildNodes.Count = 0 Then
            Dim SingleLine As New List(Of String)
            Dim HasQuite As Boolean = False
            Dim strCondition As String = CondXml.GetAttribute("Condition")
            Dim strList As List(Of String) = GetSyntaxToken(strCondition)
            Dim strWord As String = String.Empty
            If strList.Count = 1 Then
                If CondXml.GetAttribute("NOT") = "True" Then
                    SingleLine.Add("NOT")
                End If
            End If
            For i As Byte = 0 To strList.Count - 1
                strWord = strList(i)
                Select Case strWord
                    Case "=", "<=", ">="
                        If CondXml.GetAttribute("NOT") = "True" Then
                            SingleLine.Add("NOT")
                        End If
                        SingleLine.Add(strWord)
                    Case "''"
                        If i = strList.Count - 1 Then
                            '如果是末尾的‘’进行简单的NULL的处理
                            If strList.Count = 3 Then
                                'A opr B
                                Dim DataItemName As String = strList(0)
                                '获得数据名称
                                DataItemName = DataItemName.Split(".")(DataItemName.Split(".").Length - 1)
                                Dim resultXml As XmlElement = clsDataAssist.GetDataItemByDataName(DataItemName)
                                If Not resultXml Is Nothing Then
                                    '查询数据类型(这个版本暂时认为所有同名元素，类型相同)
                                    Select Case resultXml.GetAttribute("TYPE")
                                        Case "CHAR"
                                            SingleLine.Add("SPACE")
                                        Case "FIXED DEC"
                                            SingleLine.Add("ZERO")
                                        Case "PTR"
                                            SingleLine.Add("NULL")
                                        Case Else
                                            SingleLine.Add(strWord)
                                    End Select
                                Else
                                    SingleLine.Add(strWord)
                                End If
                            End If
                        Else
                            SingleLine.Add(strWord)
                        End If
                    Case Else
                        SingleLine.Add(clsJustifyStatement.ModifyVarName(strWord))
                End Select
            Next
            If CondXml.GetAttribute("LOGIC") <> String.Empty Then
                SingleLine.Add(CondXml.GetAttribute("LOGIC"))
            End If
            '输入条件式,前面补足括号
            rtnCondition.Add(Join(SingleLine.ToArray))
        Else
            For Each SubCondNode As XmlElement In CondXml.ChildNodes
                For Each StrLine As String In ReWriteCondition(SubCondNode)
                    rtnCondition.Add(StrLine)
                Next
            Next
            '非顶层计算式,添加括号
            If Not CondXml.ParentNode Is Nothing Then
                rtnCondition.Item(0) = "(" & rtnCondition.Item(0)
                For t As Integer = 1 To rtnCondition.Count - 2
                    rtnCondition.Item(t) = Space(1) & rtnCondition.Item(t)
                Next
                rtnCondition.Item(rtnCondition.Count - 1) = Space(1) & rtnCondition.Item(rtnCondition.Count - 1) & ")"
            End If
            If CondXml.GetAttribute("LOGIC") <> String.Empty Then
                rtnCondition.Item(rtnCondition.Count - 1) &= Space(Indent) & CondXml.GetAttribute("LOGIC")
            End If
        End If
        Return rtnCondition
    End Function
    ''' <summary>
    ''' 递归用条件式预处理
    ''' </summary>
    ''' <param name="ConditionXml"></param>
    ''' <param name="PreProcess"></param>
    ''' <param name="AfterProcess"></param>
    ''' <remarks></remarks>
    Public Sub ConditionProcess(ByVal ConditionXml As XmlElement, ByVal PreProcess As clsStatementBlock, ByVal AfterProcess As clsStatementBlock)
        Dim strCondition As String = ConditionXml.GetAttribute("Condition")
        Dim conditionWords As List(Of String) = GetSyntaxToken(strCondition)
        '=左边的表达式
        Dim LeftExpress As String = String.Empty
        '=右边的表达式
        Dim RightExpress As String = String.Empty
        '是否放入右边
        Dim IsPutWordToRightExpress As Boolean = False
        '是否有NOT
        Dim IsHasNot As Boolean = False
        '运算符号
        Dim BooleanOpr As String = String.Empty
        For Each strWord As String In conditionWords
            Select Case strWord
                Case "=", "<", ">", "<=", ">="
                    IsPutWordToRightExpress = True
                    BooleanOpr = strWord
                Case "NOT"
                    IsHasNot = True
                Case Else
                    If IsPutWordToRightExpress Then
                        RightExpress &= Space(1) & strWord
                    Else
                        LeftExpress &= Space(1) & strWord
                    End If
            End Select
        Next
        '进行顶级调整
        LeftExpress = ModifySubExpress(LeftExpress, PreProcess, AfterProcess)
        RightExpress = ModifySubExpress(RightExpress, PreProcess, AfterProcess)
        mCondition = LeftExpress & Space(1) & BooleanOpr & Space(1) & RightExpress
        ConditionXml.SetAttribute("Condition", mCondition)
        If ConditionXml.HasChildNodes Then
            For Each SubCon As XmlElement In ConditionXml.ChildNodes
                ConditionProcess(SubCon, PreProcess, AfterProcess)
            Next
        End If
    End Sub
End Class
